package com.killer_jin.core.common.util;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.InputStream;
import java.net.URL;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * OSS 上传文件工具类
 *
 * @author wza
 * @since 2019/3/21
 */
public class OssUtil {
    private String accessKeySecret;
    private String accessKeyId;
    private String endpoint;
    private String bucketName;
    private OSSClient ossClient;

    /**
     * 构造器，初始化参数。并实例化ossClient对象
     *
     * @param endpoint        bucketNmae
     * @param accessKeyId     accessKeyId
     * @param accessKeySecret accessKeySecret
     * @param bucketName      bucketName
     */
    public OssUtil(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) {
        this.endpoint = endpoint;
        this.accessKeySecret = accessKeySecret;
        this.accessKeyId = accessKeyId;
        this.bucketName = bucketName;

        //实例化ossClient
        ossClient = new OSSClient(this.endpoint, this.accessKeyId, this.accessKeySecret);

    }

    /**
     * 判断OSS服务文件上传时文件的contentType
     *
     * @param fileSuffix 文件后缀
     * @return contentType
     * @author wza
     */
    public static String getContentType(String fileSuffix) {

        if (".bmp".equalsIgnoreCase(fileSuffix)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileSuffix)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileSuffix) ||
                ".jpg".equalsIgnoreCase(fileSuffix) ||
                ".png".equalsIgnoreCase(fileSuffix) ||
                ".jpz".equalsIgnoreCase(fileSuffix)) {
            return "image/jpeg";
        }
        if (".html".equalsIgnoreCase(fileSuffix) ||
                ".htm".equalsIgnoreCase(fileSuffix) ||
                ".hts".equalsIgnoreCase(fileSuffix)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileSuffix)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileSuffix)) {
            return "application/vnd.visio";
        }
        if (".pptx".equalsIgnoreCase(fileSuffix) ||
                ".ppt".equalsIgnoreCase(fileSuffix)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".docx".equalsIgnoreCase(fileSuffix) ||
                ".doc".equalsIgnoreCase(fileSuffix)) {
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(fileSuffix)) {
            return "text/xml";
        }
        if (".xls".equalsIgnoreCase(fileSuffix)) {
            return "application/vnd.ms-excel";
        }
        if (".xlsx".equalsIgnoreCase(fileSuffix)) {
            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        }
        if (".zip".equalsIgnoreCase(fileSuffix)) {
            return "application/zip";
        }
        return null;
    }

    /**
     * 根据流上传文件
     *
     * @param inputStream 流
     * @param fileName    文件名称
     * @param uploadPath  文件夹路径
     * @return 上传结果
     * @author wza
     */
    public boolean uploadFileOSS(InputStream inputStream, String fileName, String uploadPath) {
        try {
            //判断bucket是否存在
            ensureBucket();
            //获取上传文件后缀名
            String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
            //创建上传Object的Metadata。ObjectMetaData是用户对该object的描述
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setContentEncoding("utf-8");
            //获取文件类型
            objectMetadata.setContentType(getContentType(fileSuffix));
            objectMetadata.setContentDisposition("attachment;filename=" + fileName);
            ossClient.putObject(bucketName, uploadPath, inputStream, objectMetadata);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 判断bucket存储空间是否已建立
     * 若未建立，先创建一个Bucket
     *
     * @throws OSSException    异常抛出
     * @throws ClientException 异常抛出
     * @author wza
     */
    private void ensureBucket() throws OSSException, ClientException {
        //判断bucket是否存在
        boolean exists = ossClient.doesBucketExist(bucketName);
        if (!exists) {
            ossClient.createBucket(bucketName);
        }
    }

    /**
     * 判断OSS服务文件上传时文件的contentType
     *
     * @param file 文件后缀
     * @return contentType
     * @author wza
     */
    public String getContentType(CommonsMultipartFile file) {
        return file.getContentType();
    }

    /**
     * 获取文件临时地址（1天）
     *
     * @param filePath bucketName下的文件路径
     * @return 路径字符串
     * @author wza
     */
    public String getFilePath(String filePath) {
        //设置有效期
        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24);
        URL url = ossClient.generatePresignedUrl(bucketName, filePath, expiration);
        return url.toString();
    }

    /**
     * 关闭ossClient对象
     *
     * @author wza
     */
    public void ossClientClose() {
        try {
            if (ossClient != null) {
                //关闭ossClient对象
                ossClient.shutdown();
                ossClient = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除某个Object
     *
     * @param bucketUrl OSS服务器路径
     * @author wza
     */
    public void deleteObject(String bucketUrl) {
        // 删除Object.
        ossClient.deleteObject(bucketName, bucketUrl);
    }

    /**
     * 删除多少天之前的文件
     *
     * @param days 天数（前几天）
     * @param path path目录下一级目录
     * @author wza
     */
    public void deleteOssFile(LocalDate date, Integer days, String path) {
        try {
            //获取前 days 天日期
            LocalDate deleteBeforeDate = date.minusDays(days);

            String deletePath = path + deleteBeforeDate.toString() + "/";

            //创建ossUtil对象
            List<String> paths = getCommonPrefixes(path);
            //循环子目录
            for (String str : paths) {

                //判断该目录是否是一周前的目录
                if (deletePath.compareTo(str) > 0) {
                    //获取该目录下所有的文件
                    List<String> prefixs = getAllKey(str);
                    prefixs.add(str);
                    //根据文件地址删除文件
                    deleteOSSFile(prefixs);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除多个Object(上限1000)
     *
     * @param bucketUrls OSS服务器路径集合
     */
    private void deleteObjects(List<String> bucketUrls) {
        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(bucketUrls));
        deleteObjectsResult.getDeletedObjects();
    }

    /**
     * OSS批量删除文件上限为1000，当文件超过1000就需要分片删除。
     *
     * @param list 文件路径集合
     * @author wza
     */
    private void deleteOSSFile(List<String> list) {
        //没有数据直接返回
        if (list == null || list.size() == 0) {
            return;
        }

        //文件总数
        int size = list.size();
        //文件大于1000时 需要进行分片删除
        if (size > 1000) {
            int count = size / 1000;
            //以一千一次切分集合 进行删除
            for (int i = 0; i < count; i++) {

                List<String> parts = list.subList(i * 1000, (i + 1) * 1000);
                deleteObjects(parts);
            }
            if (count % 1000 > 0) {
                deleteObjects(list.subList(count * 1000, size));
            }
        } else {
            deleteObjects(list);
        }
    }

    /**
     * 列出目录下所有文件(object)
     *
     * @param prefix 指定文件夹
     * @return 所有文件路径集合
     * @author wza
     */
    private List<String> getAllKey(String prefix) {
        List<String> list = new ArrayList<>();
        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
        // 递归列出fun目录下的所有文件
        listObjectsRequest.setPrefix(prefix);
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
            list.add(objectSummary.getKey());
        }
        return list;
    }

    /**
     * 列出目录下当前子目录
     *
     * @param prefix 指定文件夹
     * @return 子目录路径结果集
     * @author wza
     */
    private List<String> getCommonPrefixes(String prefix) {
        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
        // "/" 为文件夹的分隔符
        listObjectsRequest.setDelimiter("/");
        // 递归列出fun目录下的所有文件
        listObjectsRequest.setPrefix(prefix);
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
        return listing.getCommonPrefixes();
    }

    /**
     * 删除多少天之前的文件
     *
     * @param day  天数（前几天）
     * @param path path目录下一级目录 路径的命名格式一定要是（yyyyMMdd）
     * @author wza
     */
    // public void deleteOssFile(Integer day, String path) {
    //     try {
    //         //获取前 day 天日期
    //         Date date = TimeTools.subDays(new Date(), day);
    //         Integer datePath = Integer.parseInt(TimeTools.formatDate(date, "yyyyMMdd"));
    //         //创建ossUtil对象
    //         //获取 coil-core-number-file 目录下的子目录
    //         List<String> paths = getCommonPrefixes(path);
    //         //循环子目录
    //         for (String str : paths) {
    //             Integer dateFile = Integer.parseInt(str.substring(path.length(), str.length()-1));
    //             //判断该目录是否是一周前的目录
    //             if (dateFile < datePath) {
    //                 //获取所有该子目录下所有文件地址的集合
    //                 List<String> prefixs = getAllKey(str);
    //                 prefixs.add(str);
    //                 //根据文件地址删除文件
    //                 deleteOSSFile(prefixs);
    //             }
    //         }
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    // }

}
